package com.cupcakeengine.events
{
	import com.cupcakeengine.utils.Delegate;
	import flash.events.Event;
	import flash.utils.Dictionary;
	
	public class EventBroadcaster
	{
		// ___________________________________________________________________ CONSTANTS
		static public const CONTEXT_ALL			: int = -1;
		
		// ___________________________________________________________________ CLASS PROPERTIES
		static private var _count				: int;
		static private var _wasInit				: Boolean;
		static private var _automaticInit		: Boolean = true;
		
		// ___________________________________________________________________ INSTANCE PROPERTIES
		static protected var _source			: Object;
		static protected var _dEvtHolders		: Dictionary;
		
		// ___________________________________________________________________ GETTERS AND SETTERS
		public function get automaticInit () 					: Boolean { return _automaticInit; }
		public function set automaticInit ( value : Boolean ) 	: void
		{
			_automaticInit = value;
		}
		
		// ___________________________________________________________________ CONSTRUCTOR
		
		// ___________________________________________________________________ PUBLIC METHODS
		/**
		 * 
		 */
		static public function init( source : Object = null ) : void
		{
			if (_wasInit) { return; }
			
			_dEvtHolders		= new Dictionary(true);
			_source				= source;
			_wasInit			= true;
		}
		
		/**
		 * 
		 */
		static public function isRegistered( listener : Object, type : String = null ) : Boolean
		{
			if (!_wasInit && _automaticInit) { init(); };
			
			var retValue : Boolean = false;
			
			if (_dEvtHolders[type])
			{
				retValue = (_dEvtHolders[type] as EventHolder).isRegisteredEvtListener(listener)
			}
			
			return retValue;
		}
		
		/**
		 * 
		 */
		static public function addEventListener( type : String, listener : Object, ...rest ) : Boolean
		{
			if (!_wasInit && _automaticInit) { init(); };
			
			var retValue : Boolean = false;
			
			if ( listener is Function )
			{
				if (!_dEvtHolders[type]) 
				{
					_dEvtHolders[type] = new EventHolder(type);
				}
				
				var d : Delegate = new Delegate( listener as Function );
				if ( rest ) d.setArgumentsArray( rest );
				
				(_dEvtHolders[type] as EventHolder).addEvtListener(listener, d);
				
				retValue = true;
			} 
			else
			{
				throw( new Error( "[EventBroadcaster].addEventListener() failed," ) );
			}
			
			return retValue;
		}
		
		static public function removeEventListener( type : String, listener : Object ) : Boolean
		{
			if (!_wasInit && _automaticInit) { init(); };
			
			var retValue : Boolean = false;
			
			if ( listener is Function )
			{
				if (_dEvtHolders[type]) 
				{
					if((_dEvtHolders[type] as EventHolder).isRegisteredEvtListener( listener ))
					{
						(_dEvtHolders[type] as EventHolder).removeEvtListener( listener );
						retValue = true;
					}
				}
			}
			else
			{
				throw( new Error( "[EventBroadcaster].addEventListener() failed," ) );
			}
			
			return retValue;
		}
		
		/**
		 * 
		 */
		static public function dispatchEvent( o : Object ) : void
		{
			throw new Error("ATENCAO !!!!!    -    Usar Event Broadcaster");
			
			if (!_wasInit && _automaticInit) { init(); };
			
			if( o["type"] == null )
			{
				throw new Error( "[EventBroadcaster].dispatchEvent() fails. " + o + " event has no type." );
			}
			
			var e : BasicEvent = new BasicEvent( o["type"] );
			
			for ( var p : String in o ) 
				if (p != "type") e[p] = o[p];
				
			broadcastEvent( e );
		}
		
		/**
		 * 
		 */
		static public function broadcastEvent( e : Event ) : void
		{
			if( e.target == null && e is BasicEvent ) 
				(e as BasicEvent).target = _source;
			
			if ( _dEvtHolders[e.type] ) 
				internalBroadcastEvent( _dEvtHolders[e.type], e );
		}
		
	
		
		// ___________________________________________________________________ PRIVATE METHODS
		static protected function internalBroadcastEvent( holder : EventHolder, e : Event ) : void
		{
			var type 	: String 		= e.type;
			var hold	: EventHolder 	= holder;
			
			for each ( var listener : Object in hold.eventListeners)
			{		
				if (listener is Delegate )
				{
					(listener as Delegate).execute(e);
					
				}
			}
		}
		
		// ___________________________________________________________________ EVENTS

	}
}